package com.example.smartf.WebSocket;

import com.example.smartf.repository.mysql.UserinfoRepository;
import com.example.smartf.tool.RedisUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

//和客户端的连接URL
@ServerEndpoint("/webSocket")
//在外部tomcat上需要注释掉
@Component
//
public class WebSocketService {
    //日志记录器
    private static Logger logger = LoggerFactory.getLogger(WebSocketService.class);

    @Autowired
    private UserinfoRepository userinfoRepository;

    @Autowired
    private static UserinfoRepository staticuserinfoRepository;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private static RedisUtils staticredisUtils;

    @PostConstruct
    public void init(){
        staticuserinfoRepository = userinfoRepository;
        staticredisUtils = redisUtils;
    }


    //存放连接进来的客户端
    private static CopyOnWriteArrayList<WebSocketService> webSocketSet = new CopyOnWriteArrayList<WebSocketService>();

    //记录连接进来的连接数
    private static int onlineCount = 0;

    //通过session发送给用户实时数据
    private Session session;

    //创建一个线程安全的hashmap <deviceID,session>  deviceID和session对照表
    private static ConcurrentHashMap<String, List<Session>> deviceIDmap = new ConcurrentHashMap<>();

    @OnOpen
    public void OnOpen(Session session){
        this.session = session;
        webSocketSet.add(this);
        WebSocketService.onlineCount++;
        logger.info("webSocket：" + "sessionID = " + session.getId() + "连接成功，当前连接数：" + WebSocketService.onlineCount);
    }

    @OnError
    public void OnError(Session session, Throwable error){
        webSocketSet.remove(this);
        for(Map.Entry<String,List<Session>> entry : deviceIDmap.entrySet()){
            if( entry.getValue().contains(session)){
                //先取出 sessions
                List<Session> sessions = deviceIDmap.get(entry.getKey());
                //将 要删除的session 从sessions 中删除
                sessions.remove(session);
                //map中将整个 key-value删除
                deviceIDmap.remove(entry.getKey(),entry.getValue());
                //再讲 处理完的sessions 塞回去
                deviceIDmap.put(entry.getKey(),sessions);
            }
        }
        WebSocketService.onlineCount--;
        logger.warn("webSocket：" + "sessionID = " + session.getId() + "连接异常！");
        logger.error(error.toString());
    }

    @OnClose
    public synchronized void OnClose(Session session){
        while (! webSocketSet.remove(this) ){

        }
        for(Map.Entry<String,List<Session>> entry : deviceIDmap.entrySet()){
            if( entry.getValue().contains(session)){
                //先取出 sessions
                List<Session> sessions = deviceIDmap.get(entry.getKey());
                //将 要删除的session 从sessions 中删除
                sessions.remove(session);
                //map中将整个 key-value删除
                deviceIDmap.remove(entry.getKey(),entry.getValue());
                //再讲 处理完的sessions 塞回去
                deviceIDmap.put(entry.getKey(),sessions);
            }
        }
        WebSocketService.onlineCount--;
        logger.info("webSocket：" + "sessionID = " + session.getId() + "连接关闭，当前连接数：" + WebSocketService.onlineCount);
    }

    public static void sendInfo(String message , String deviceID){
        // 若usermap 即 websocket正在处于连接的用户组中 存在 要发送的username 则发送
        if( deviceIDmap.containsKey(deviceID) == true ){
            //按照device 取出对应的 sessions 遍历发送
            List<Session> sessions = deviceIDmap.get(deviceID);
            for(Session session : sessions){
                try {
                    session.getBasicRemote().sendText(message);
                    logger.info("webSocket：" + "deviceID = " + deviceID + " sessionID = " + session.getId() + " 发送消息成功！");
                }catch (Exception e){
                    logger.warn("webSocket：" + "sessionID = " + session.getId() + "发送消息异常！");

                    //将发送消息异常的 session 删除
                    for(Map.Entry<String,List<Session>> entry : deviceIDmap.entrySet()){
                        if( entry.getValue().contains(session)){
                            //先取出 sessions
                            List<Session> tempsessions = deviceIDmap.get(entry.getKey());
                            //将 要删除的session 从sessions 中删除
                            tempsessions.remove(session);
                            //map中将整个 key-value删除
                            deviceIDmap.remove(entry.getKey(),entry.getValue());
                            //再讲 处理完的sessions 塞回去
                            deviceIDmap.put(entry.getKey(),tempsessions);
                        }
                    }
                    WebSocketService.onlineCount--;
                }
            }

        }else {
            //若不存在 则直接返回
            return;
        }
    }

    @OnMessage
    public synchronized void OnMessage(String msg,Session session){
        logger.info("webSocket：" + "deviceID = " + msg + "消息接收成功！");

        //msg为deviceID， 放入deviceID-session对照表
        List<Session> sessions = deviceIDmap.get(msg);
        if(sessions == null){
            sessions = new ArrayList<Session>();
        }
        sessions.add(session);
        deviceIDmap.put(msg,sessions);

        //如果要 客户端发送消息立刻响应 则：此函数要立刻发送一条实时消息  从redis中获取
        sendInfo((String) staticredisUtils.get(msg+"_latest"),msg);
    }

    public static synchronized int getOnlineCount(){
        return WebSocketService.onlineCount;
    }
}
